﻿// Copyright (c) 2011 Blue Onion Software, All rights reserved
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;

public partial class Default : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            bool celsius;
            var location = GetLocation(Request) ?? "10001";

            if (IsPostBack)
            {
                celsius = checkboxCelsius.Checked;
                Response.Cookies["celsius"].Value = celsius ? "true" : "false";
                Response.Cookies["celsius"].Expires = DateTime.Today.AddYears(1);
            }
            else
            {
                celsius = GetCelsius(Request);
                checkboxCelsius.Checked = celsius;
            }

            var forecastUrl = "http://www.google.com/ig/api?weather=" + location;
            var forecastXml = Page.Cache[forecastUrl] as XElement ?? LoadXml(forecastUrl, "weather");
            ParseForecast(forecastXml, celsius);

            var alertUrl = "http://api.wunderground.com/auto/wui/geo/AlertsXML/index.xml?query=" + location;
            var alertXml = Page.Cache[alertUrl] as XElement ?? LoadXml(alertUrl, "");
            ParseAlerts(alertXml);

            fullweather.NavigateUrl = "http://www.wunderground.com/cgi-bin/findweather/hdfForecast?query=" +  location;

            Response.Cookies["weather"].Value = location;
            Response.Cookies["weather"].Expires = DateTime.Today.AddYears(1);
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
            Response.Cache.SetNoStore();
            Response.Charset = "utf-8";
            Response.ContentEncoding = Encoding.UTF8;
        }

        catch
        {
            Response.Redirect("Change.aspx?error=1", true);
        }
    }

    private void ParseForecast(XContainer forecastXml, bool celsius)
    {
        if (forecastXml == null)
        {
            return;
        }

        city.InnerText = forecastXml.Element("forecast_information").Element("city").FirstAttribute.Value;
        var us = forecastXml.Element("forecast_information").Element("unit_system").FirstAttribute.Value == "US";

        var currentCondtions = forecastXml.Element("current_conditions");
        weather.InnerText = currentCondtions.Element("condition").FirstAttribute.Value;
        temperature.InnerHtml = currentCondtions.Element(celsius ? "temp_c" : "temp_f").FirstAttribute.Value + "&deg;";

        humidity_wind.InnerHtml = currentCondtions.Element("humidity").FirstAttribute.Value + "<br/>" +
            currentCondtions.Element("wind_condition").FirstAttribute.Value;

        var forecasts = forecastXml.Elements("forecast_conditions").ToArray();

        day1.InnerText = WeekDay(forecasts[0]);
        Image(icon1, forecasts[0]);
        temp1.InnerHtml = HighLow(forecasts[0], us, celsius);

        day2.InnerText = WeekDay(forecasts[1]);
        Image(icon2, forecasts[1]);
        temp2.InnerHtml = HighLow(forecasts[1], us, celsius);

        day3.InnerText = WeekDay(forecasts[2]);
        Image(icon3, forecasts[2]);
        temp3.InnerHtml = HighLow(forecasts[2], us, celsius);

        day4.InnerText = WeekDay(forecasts[3]);
        Image(icon4, forecasts[3]);
        temp4.InnerHtml = HighLow(forecasts[3], us, celsius);
    }

    private void ParseAlerts(XContainer xml)
    {
        if (xml == null)
        {
            return;
        }

        try
        {
            var html = new StringBuilder();
            var alert = xml.Element("alert");

            if (alert.Attribute("count").Value != "0")
            {
                foreach (var alertItem in alert.Elements("AlertItem"))
                {
                    html.AppendFormat(
                        "<p><span style=\"color: #990000\">{0}</span><br/>Date: {1}<br/>Expires: {2}<hr/>{3}</p>",
                        HttpUtility.HtmlEncode(alertItem.Element("description").Value),
                        HttpUtility.HtmlEncode(alertItem.Element("date").Value),
                        HttpUtility.HtmlEncode(alertItem.Element("expires").Value),
                        HttpUtility.HtmlEncode(alertItem.Element("message").Value));
                }

                alerts.Text = html.ToString();
            }
        }
        // ReSharper disable EmptyGeneralCatchClause
        catch
        {
        }
        // ReSharper restore EmptyGeneralCatchClause
    }

    private XElement LoadXml(string url, string element)
    {
        XElement xml;
        var request = (HttpWebRequest)WebRequest.Create(url);
        var response = (HttpWebResponse)request.GetResponse();

        using (var stream = new StreamReader(response.GetResponseStream(), Encoding.UTF7))
        {
            if (response.StatusCode != HttpStatusCode.OK)
            {
                return null;
            }

            xml = XElement.Load(stream);

            if (string.IsNullOrEmpty(element) == false)
            {
                xml = xml.Element(element);
            }

            if (xml != null)
            {
                Page.Cache.Add(url, xml, null, DateTime.Now.AddMinutes(15),
                               Cache.NoSlidingExpiration,
                               CacheItemPriority.Normal, null);
            }
        }

        return xml;
    }

    public static string GetLocation(HttpRequest request)
    {
        var location = request.Params["l"];
        if (string.IsNullOrWhiteSpace(location))
        {
            var cookie = request.Cookies["weather"];
            location = (cookie == null) ? null : cookie.Value;
        }
        return location;
    }

    public static bool GetCelsius(HttpRequest request)
    {
        var cookie = request.Cookies["celsius"];
        return (cookie != null) ? cookie.Value == "true" : false;
    }

    private static string WeekDay(XContainer forecast)
    {
        return forecast.Element("day_of_week").FirstAttribute.Value;
    }

    // http://google.com/ig/images/weather/chance_of_storm.gif
    // http://www.google.com/ig/images/weather/chance_of_rain.gif

    private static void Image(Image icon, XContainer forecast)
    {
        var imageUrl = forecast.Element("icon").FirstAttribute.Value;
        if (string.IsNullOrWhiteSpace(imageUrl))
        {
            imageUrl = "images/na.gif";
        }
        if (imageUrl.Contains("/ig/images/weather/"))
        {
            imageUrl = "http://www.google.com" + imageUrl;
        }
        icon.ImageUrl = imageUrl;
        var alternateText = forecast.Element("condition").FirstAttribute.Value;
        icon.AlternateText =  (string.IsNullOrWhiteSpace(alternateText))
            ? "Not Available" 
            : alternateText;
        icon.ToolTip = icon.AlternateText;
    }

    private static string HighLow(XContainer forecast, bool us, bool inCelsius)
    {
        return string.Format("{0}&deg;<br/>{1}&deg;",
                             AsTemp(forecast.Element("high").FirstAttribute.Value, us, inCelsius),
                             AsTemp(forecast.Element("low").FirstAttribute.Value, us, inCelsius));
    }

    private static string AsTemp(string value, bool us, bool inCelsius)
    {
        var temperature = int.Parse(value);

        if (temperature == int.MinValue)
        {
            return "??";
        }

        if (us && inCelsius)
        {
            temperature = (int)Math.Round((5.0 / 9.0) * (temperature - 32));
        }

        if (!us && !inCelsius)
        {
            temperature = (int)Math.Round(((9.0 / 5.0) * temperature) + 32);
        }

        return temperature.ToString();
    }
}